package org.rost.web.thrithon.core;

import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.xml.sax.Attributes;

public class ThrithonRequestContext {
    
    private String contextPath = "";
    private String servletPath = "";
    private String currentDir = "";
    private List<String> parameters = new ArrayList<String>();
    private String template = "";
    private HttpServletRequest request = null;
    private HttpServletResponse response = null;
    private OutputStream stream = null;
    private Map<String, Object> attributes = new HashMap<String, Object>();
    private Attributes saxAttributes = null;
    
    /**
     * Returns current context path
     * @return context path
     */
    public String getContextPath() {
        return contextPath;
    }

    void setContextPath(String contextPath) {
        this.contextPath = contextPath;
    }

    /**
     * Returns current servlet path
     * @return servlet path
     */
    public String getServletPath() {
        return servletPath;
    }

    void setServletPath(String servletPath) {
        this.servletPath = servletPath;
    }

    /**
     * Returns list of parameters passed in URL
     * @return list of parameters passed in URL
     */
    public List<String> getParameters() {
        return parameters;
    }

    void setParameters(List<String> parameters) {
        this.parameters = parameters;
    }

    /**
     * Returns template of current generated page
     * @return 
     */
    public String getTemplate() {
        return template;
    }

    /**
     * Sets template for response
     * @param template - address of template to
     */
    public void setTemplate(String template) {
        this.template = template;
    }

    public HttpServletRequest getRequest() {
        return request;
    }

    void setRequest(HttpServletRequest request) {
        this.request = request;
    }

    public HttpServletResponse getResponse() {
        return response;
    }

    void setResponse(HttpServletResponse response) {
        this.response = response;
    }

    public OutputStream getStream() {
        return stream;
    }

    public void setStream(OutputStream stream) {
        this.stream = stream;
    }
    
    Object getBean(String beanName, String scope){
        try {

            String className = beanName;
            for (BeanDefinition beanDefinition : ThrithonAppContext.getContext().getBeans()) {
//                EngineAppContext.log("Bean: "+beanDefinition);
                if (beanDefinition.getAlias().equals(beanName)) {
                    className = beanDefinition.getClassName();
                    if (scope == null) {
                        scope = beanDefinition.getScope();
                    }
                    break;
                }
            }
//            EngineAppContext.log("Creating: "+className);
            Class _class = Class.forName(className);
            Object obj = null;
            if ("request".equals(scope) || scope == null || "".equals(scope)) {
                //Search in request
                if (getRequest().getAttribute(beanName) != null) {
                    obj = getRequest().getAttribute(beanName);
                } else {
                    obj = _class.newInstance();
                    getRequest().setAttribute(beanName, obj);
                }
            }
            if ("session".equals(scope)) {
                if (getRequest().getSession().getAttribute(beanName) != null) {
                    obj = getRequest().getSession().getAttribute(beanName);
                } else {
                    obj = _class.newInstance();
                    getRequest().getSession().setAttribute(beanName, obj);
                }
            }
            if ("application".equals(scope) || "app".equals(scope)) {
                if (ThrithonAppContext.getContext().getServletContext().getAttribute(beanName) != null) {
                    obj = ThrithonAppContext.getContext().getServletContext().getAttribute(beanName);
                } else {
                    obj = _class.newInstance();
                    ThrithonAppContext.getContext().getServletContext().setAttribute(beanName, obj);
                }
            }
            return obj;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }
    
    Object callBean(String callString, String scope){
        try {
            if(callString.indexOf(".")==-1)
                throw new ThrithonException("No method definition in call string ["+callString+"]");
            String object = callString.substring(0, callString.lastIndexOf("."));
            String method = callString.substring(callString.lastIndexOf(".")+1);
            ThrithonAppContext.log("object = "+object+", method = "+method);
            Object obj = getBean(object, scope);
            
            Method m = obj.getClass().getMethod(method, getClass());
            Object result = m.invoke(obj, this);
            return result;
        } catch (Exception ex) {
            ex.printStackTrace();
            ThrithonAppContext.log(ex.toString());
        }
        return null;
    }
    
    void callAction(String callString){
        for (ActionDefinition actionDefinition : ThrithonAppContext.getContext().getActions()) {
            if(actionDefinition.getAlias().equals(callString)){
                callString = actionDefinition.getMethod();
                break;
            }
        }
        Object obj = callBean(callString, null);
        if(obj!=null)
            setAttribute("actionResult", obj);
    }

    public void setAttribute(String name, Object obj){
        attributes.put(name, obj);
    }
    
    public Object getAttribute(String name){
        return attributes.get(name);
    }

    public Attributes getSaxAttributes() {
        return saxAttributes;
    }

    void setSaxAttributes(Attributes saxAttributes) {
        this.saxAttributes = saxAttributes;
    }

    public String getCurrentDir() {
        return currentDir;
    }

    public void setCurrentDir(String currentDir) {
        this.currentDir = currentDir;
    }
    
    String getHTMLPath(String path){
        if(path.startsWith("/"))
            return getContextPath()+path;
        return getContextPath()+getCurrentDir()+path;
    }
}
